﻿using EOSDigital.API;
using EOSDigital.SDK;
using LogLib;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Text;
using static System.Net.WebRequestMethods;
using System.Threading;
using SeekOrigin = System.IO.SeekOrigin;

namespace NewCapturerDemo.DSLR
{
	public class CanonDSLRCamera
	{
        #region static fields
		private static Mutex mutex = null;
        private static MemoryMappedFile mmFile = null;
        /// <summary>
        ///  Share the Mutex Name with all users.
        /// </summary>
        public const string MutexName = "MemoryMapMutex";

        /// <summary>
        /// Set the Memory Capacity
        /// </summary>
        public const long MemoryCapacity = 104857600;

        /// <summary>
        /// Share The Memory Mapped File Name with all users.
        /// </summary>
        public const string MappedFileName = "CanonEOS";

		static CanonDSLRCamera()
		{

		}

        public static void CreatMutex()
		{
			if(mutex != null)
			{
				return;
			}
            bool mutexCreated = false;
            mutex = new Mutex(false, MutexName, out mutexCreated);
            if (!mutexCreated)
            {
                mutex = Mutex.OpenExisting(MutexName);
            }
            mmFile = MemoryMappedFile.CreateOrOpen(MappedFileName, MemoryCapacity, MemoryMappedFileAccess.ReadWrite);
        }

        /// <summary>
        /// jiang bitmap bytes xie ru gongxiang nei cun wen jian
        /// </summary>
        /// <param name="bitmap"></param>
        private static void WriteByteDataToMemoryMappedFile(Bitmap bitmap)
		{ 
			try
			{
                mutex.WaitOne(1000);
                byte[] data;
                long length = 0;
                using (MemoryStream stream = new MemoryStream())
                {
                    bitmap.Save(stream, ImageFormat.Bmp);
                    length = stream.Length;
                    data = new byte[length];
                    stream.Seek(0, SeekOrigin.Begin);
					int writeLen = Convert.ToInt32(length);
                    stream.Read(data, 0, writeLen);
					Log.WriteAsync($"照片数据长度:{length}, 写入流缓存数据长度: {writeLen}");
                }

                // 首先写入数据流的长度
                using (MemoryMappedViewStream stream = mmFile.CreateViewStream(0, 8))
                {
                    var writer = new BinaryWriter(stream);
                    writer.Write(length);
                }

                //创建文件内存视图流
                // 将byte[]写入数据流
                using (MemoryMappedViewStream stream = mmFile.CreateViewStream(8, 0))
                {
                    var writer = new BinaryWriter(stream);
                    writer.Write(data);
                }
            }
			catch (Exception ex)
			{
				Log.WriteExceptionAsync(ex.ToString());
			}
            finally
			{
				mutex.ReleaseMutex();
			}
        }

        /// <summary>
        /// jiang bitmap bytes xie ru gongxiang nei cun wen jian
        /// </summary>
        /// <param name="bitmap"></param>
        private static void WriteByteDataToMemoryMappedFile(Stream stream)
        {
			try
			{
                mutex.WaitOne(1000);
                long length = stream.Length;
                byte[] data = new byte[length];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(data, 0, Convert.ToInt32(length));

                // 首先写入数据流的长度
                using (MemoryMappedViewStream mmvStream = mmFile.CreateViewStream(0, 8))
                {
                    var writer = new BinaryWriter(mmvStream);
                    writer.Write(length);
                }

                //创建文件内存视图流
                // 将byte[]写入数据流
                using (MemoryMappedViewStream mmvStream = mmFile.CreateViewStream(8, 0))
                {
                    var writer = new BinaryWriter(mmvStream);
                    writer.Write(data);
                }
            }
			catch (Exception ex)
			{
				Log.WriteExceptionAsync(ex.ToString());
			}
			finally
			{ 
				mutex.ReleaseMutex(); 
			}
        }
        #endregion

        public CanonAPI _apiHandler;

		public EOSDigital.API.Camera MainCamera;

		private readonly object _lvLock = new object();

		private Bitmap _evfBmp;

		private string _deviceName;

        private RotateFlipType _rotateSave = RotateFlipType.Rotate270FlipX;

        public bool IsRunning
		{
			get
			{
				if (this.MainCamera != null)
				{
					return this.MainCamera.IsLiveViewOn;
				}
				return false;
			}
		}

		public bool IsConnected
		{
			get
			{
				if (this.MainCamera != null)
				{
					return true;
				}
				return false;
			}
		}

		public event NewFrameEventHandler NewFrame;

		public event NewFrameEventHandler SnapshotFrame;

		public event ErrorHandler Error;

		public CanonDSLRCamera()
		{
			EOSDigital.API.ErrorHandler.NonSevereErrorHappened += this.ErrorHandler_NonSevereErrorHappened;
			EOSDigital.API.ErrorHandler.SevereErrorHappened += this.ErrorHandler_SevereErrorHappened;
		}

		private void ErrorHandler_SevereErrorHappened(object sender, Exception ex)
		{
			if (this.Error != null)
			{
				this.Error(this, ex.Message);
			}
		}

		private void ErrorHandler_NonSevereErrorHappened(object sender, ErrorCode ex)
		{
			if (this.Error != null)
			{
				this.Error(this, ex.ToString());
			}
		}

		public string[] GetCameraNames()
		{
			if (this._apiHandler == null)
			{
				this._apiHandler = new CanonAPI();
			}
			List<EOSDigital.API.Camera> cameraList = this._apiHandler.GetCameraList();
			List<string> list = new List<string>();
			foreach (EOSDigital.API.Camera item in cameraList)
			{
				list.Add(item.DeviceName);
			}
			return list.ToArray();
		}

		public bool CheckCaptureDevice(string deviceName = null)
		{
			string[] cameraNames = this.GetCameraNames();
			if (cameraNames.Any())
			{
				return true;
			}
			return false;
		}

		public bool Connect(string deviceName)
		{
			this._deviceName = deviceName;
			if (this._apiHandler == null)
			{
				this._apiHandler = new CanonAPI();
			}
			List<EOSDigital.API.Camera> cameraList = this._apiHandler.GetCameraList();
			foreach (EOSDigital.API.Camera item in cameraList)
			{
				if (!string.IsNullOrEmpty(deviceName) && !(item.DeviceName == deviceName))
				{
					continue;
				}
				this.MainCamera = item;
				this.MainCamera.OpenSession();
				this.MainCamera.LiveViewUpdatedWithEvfData += this.MainCamera_LiveViewUpdated;
				this.MainCamera.DownloadReady += this.MainCamera_DownloadReady;
				this.MainCamera.SetSetting(PropertyID.SaveTo, 2, 0);
				this.MainCamera.SetCapacity(4096, 2147483647);
				return true;
			}
			return false;
		}

		public void Disconnect()
		{
			if (this.MainCamera != null)
			{
				try
				{
					this.MainCamera.CloseSession();
				}
				catch (Exception ex)
				{
					Log.WriteExceptionAsync(ex.ToString());
				}
			}
			if (this._apiHandler != null)
			{
				try
				{
					this._apiHandler.Dispose();
				}
				catch (Exception ex)
				{
                    Log.WriteExceptionAsync(ex.ToString());
                }
			}
			this.MainCamera = null;
			this._apiHandler = null;
		}

		public string DisplayPropertyPage(IntPtr parentWindow)
		{
			throw new NotImplementedException();
		}

		public void SimulateTrigger()
		{
			this.MainCamera.TakePhotoShutterAsync();
		}

		public void AutoFocus()
		{
			this.MainCamera.TakePhotoShutterHalfWayAsync();
		}

		public void StartLiveView()
		{
			this.MainCamera.StartLiveView();
		}

		public void StopLiveView()
		{
			if (this.MainCamera.IsLiveViewOn)
			{
				this.MainCamera.StopLiveView(true);
			}
		}

		public void SetCameraParams(object obj)
		{
		}

		public void SetProperty(string strName, double strValue)
		{
			throw new NotImplementedException();
		}

		public double GetProperty(string strName)
		{
			throw new NotImplementedException();
		}

		private void MainCamera_LiveViewUpdated(EOSDigital.API.Camera sender, Stream img, EvfDataSet evfData)
		{
			lock (this._lvLock)
			{
				if (this._evfBmp != null)
				{
					this._evfBmp.Dispose();
				}
				this._evfBmp = new Bitmap(img);
			}
			if (this.NewFrame != null)
			{
				this.NewFrame(this, new NewFrameEventArgs(this._evfBmp, evfData));
			}
		}

		protected IFormatProvider ifp = new CultureInfo("zh-CN", true);

		private void MainCamera_DownloadReady(EOSDigital.API.Camera sender, DownloadInfo info)
		{
			Log.WriteAsync($"收到来自相机的下载文件请求:CamRef={info.Reference}, ItemInfo={info.ItemInfo}");
			// 先保存到默认照片目录
			//string BaseDir = DirConfig.TodayDirectory;
			//string fileName = DateTime.Now.ToString("yyyyMMddHHmmss", ifp);
			//fileName = $"{BaseDir}\\{fileName}_{info.FileName}.jpg";
			//sender.DownloadToFile(info, fileName);
			try
			{
				using (Stream stream = sender.DownloadFile(info))
				{
					using (Bitmap frame = new Bitmap(stream))
					{
						Bitmap bitmap = ComLib.ComFun.BitmapFunc.Clone(frame);
						bitmap.RotateFlip(this._rotateSave);
						WriteByteDataToMemoryMappedFile(bitmap);
						Log.WriteAsync($"照片数据{info.FileName}写入共享内存文件成功!");
						bitmap.Dispose();
						bitmap = null;
						this.SnapshotFrame?.Invoke(this, new NewFrameEventArgs(frame, default(EvfDataSet)));
					}
				}
			}
			catch (Exception ex)
			{
				Log.WriteAsync($"下载照片{info.FileName}发生了异常: {ex.Message}");
				Log.WriteExceptionAsync(ex.ToString());
			}
		}

	}
}
